package com.zsy._21生产者与消费者问题;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 等待通知范式：加锁-循环-逻辑
 *
 * @author zhangshuaiyin
 * @date 2022/6/11 20:45
 */
@SuppressWarnings("ALL")
public class WaitNotify {
    static boolean flag = true;
    static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Wait(), "WaitThread1").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(new Wait(), "WaitThread2").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(new Notify(), "NotifyThread1").start();
        new Thread(new Notify(), "NotifyThread2").start();
    }

    static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread().getName() + "flag is true. wait @ "
                                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 条件满足时，完成工作
                System.out.println(Thread.currentThread().getName() + "flag is false. running @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void run() {
            // 加锁，拥有lock的Monitor
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + "hold lock. notify @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                // 如果有两次wait，只有一个线程调用notify()方法，可能导致一个线程一致 waiting
                lock.notify();
                // lock.notifyAll();
                flag = false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 再次加锁
            synchronized (lock) {
                // 条件满足时，完成工作
                System.out.println(Thread.currentThread().getName() + "hold lock again. sleep @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
